import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;

class MDHandler extends Thread 
{ 
	private Socket clientSock;
    private MDServer chatServer;
    String username;
    MDHandler(Socket s, MDServer cs, String name) 
    {
        clientSock = s;   chatServer = cs; username = name;
    }
    
    public void sendShapeObjects(){
    	
    	ObjectOutputStream oos;
		try {
			oos = new ObjectOutputStream(clientSock.getOutputStream());
			oos.writeObject(chatServer.ShapeObjects);
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
	public void run() 
    {
    	sendShapeObjects();
    	sendToolKits();
    	chatServer.broadcastUserList();
    	
        try 
        {   
        	
        	Scanner in =
              new Scanner(clientSock.getInputStream());
            PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSock.getOutputStream()),true);
            out.println("<<USRMSG>>>>>> Welcome to the MD Server <<<<<<USRMSG>>");
            out.println("<<USRMSG>>Type \'bye\' to exit MD system.<<USRMSG>>");
            chatServer.broadcast("<<USRMSG>>" + username + " has joined discussion.<<USRMSG>>", "Chat Server");
            chatServer.broadcast("<<OWNR>> " + chatServer.ownerOfControl, "MDServer");
            while (true) 	
            {
            	String message = in.nextLine().trim();
            	if (message.equals("bye")) 
                {
            	    chatServer.broadcast(username + " has left discussion.", "Chat Server");
            	    break;
                }else if(message.contains("<<RQSTOWNR>>")){
                	chatServer.broadcast("<<OWNR>> " + chatServer.ownerOfControl, "MDServer");
                }else if(message.contains("<<REF>>")){
            		chatServer.broadcastAndLast("<<REFSHAPEOBJS>>");
            		chatServer.broadcastShapeObjects();
                }else if(message.contains("<<REFALLREADY>>")){
            		chatServer.broadcastShapeObjects();
                }else if(message.contains("<<UPDATESHAPES>>")){
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
            	    p.println("<<READY>>");	
                	getShapeObjects();
                	p.println("<<GOTEM>>");
                }else if(message.contains("USRMSG")){
                	chatServer.broadcast(message,username);
                }else if(message.contains("<<GETALLFILENAMES>>")){
                	File dir = new File("Drawings");
                	String[] filenames = dir.list();
                	for(String s: filenames){
                		chatServer.broadcast("<<FILENAME>>"+ s,username);                		
                	}
                }else if(message.contains("<<NEWDRAWING>>")){
                	chatServer.ShapeObjects.clear();
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println("<<GOTEM>>");
                	chatServer.setFileName("");
                }else if(message.contains("<<GETFILENAME>>")){ 
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println("<<RETURNFILENAME>>"+chatServer.getFileName());
                }else if(message.contains("<<SAVEFILE>>")){ 
                	String fileName = message.replace("<<SAVEFILE>>", "Drawings/");
                	ObjectOutputStream oos;
            		try{
            			oos = new ObjectOutputStream(new FileOutputStream(fileName));
            		    oos.writeObject(chatServer.ShapeObjects);
            		    oos.close();
            		    chatServer.setFileName(fileName);
            		    chatServer.broadcast("<<USRMSG>>Saved drawing as "
            		    		+fileName.replace("Drawings/", "")+"<<USRMSG>>", username);
            		}catch(FileNotFoundException fnfe){
            			System.out.println("FileNotFoundException"); 
            		}catch(IOException ioe){
            			System.out.println("IOException");
            		}
                }else if(message.contains("<<DELETEFILE>>")){ 
                	String delFile = message.replace("<<DELETEFILE>>", "");
                	File file = new File(delFile);
                	if(file.delete()){
	                	if(delFile.equals(chatServer.getFileName())){
	                		chatServer.setFileName("");
	                		chatServer.ShapeObjects.clear();
	                	}
	                	chatServer.broadcast("<<USRMSG>>Deleted drawing "
            		    		+delFile.replace("Drawings/", "")+"<<USRMSG>>", username);
	                	System.out.println("done deleting "+delFile);
                	}else{
                		System.out.println("ERROR deleting "+delFile);
                	}
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println("<<GOTEM>>");
                }else if(message.contains("<<DOWNLOADFILE>>")){ 
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println(message);
                }else if(message.contains("<<READYTODOWNLOADFILE>>")){ 
                	String downFile = message.replace("<<READYTODOWNLOADFILE>>", "");
                	ObjectInputStream ois;
            	    Object ob = null;
            	    ois = new ObjectInputStream(new FileInputStream(downFile));
            	    ob = ois.readObject();
                	
                	if(ob != null){
	         			ObjectOutputStream oos;
	         			try {
	         				oos = new ObjectOutputStream(clientSock.getOutputStream());
	         				oos.writeObject(ob);
	         			} catch (IOException ioe) {
	         				ioe.printStackTrace();
	         			}
                	 }
                }else if(message.contains("<<OPENDRAWING>>")){
                	System.out.println("opening");
                	String fileName = message.replace("<<OPENDRAWING>>", "");
                	ObjectInputStream ois;
            	    Object ob = null;
            	    try{
            	        ois = new ObjectInputStream(new FileInputStream(fileName));
            	        ob = ois.readObject();
            	        chatServer.ShapeObjects = (LinkedList<ShapeObject>)ob;
            	        chatServer.setFileName(fileName.replace("Drawings/", ""));
            	        chatServer.broadcast("<<USRMSG>>Opened file "+fileName.replace("Drawings/", "")+"<<USRMSG>>", username);
            	    }catch(ClassCastException cce){
            	    	System.out.println("ClassCastException");
            	    }catch(ClassNotFoundException cnfe){
            	    	System.out.println("ClassNotFoundException");
            	    }catch(FileNotFoundException fnfe){
            	    	System.out.println("FileNotFoundException");
            	    }catch(IOException ioe){
            	    	System.out.println("IOException");
            	    }
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println("<<GOTEM>>");
                }
                else if(message.contains("<<UPLOADFILE>>")){
                	String fn = message.replace("<<UPLOADFILE>>", "");
                	File dir = new File ("Drawings/");
            		String[] filenames = dir.list();
            		boolean duplicate = false;
                	for(String s: filenames){
                		if (s.equals(fn)){
                			duplicate = true;
                		}
                	}
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	if(duplicate){
	                	p.println("<<DUPLICATE>>"+fn);
	                	System.out.println("<<DUPLICATE>>"+fn);
                	}else{
	                	p.println("<<READYFORDRAWINGUPLOAD>>");
	                	ObjectInputStream ois = new ObjectInputStream(clientSock.getInputStream());
	                	try {
	                		LinkedList drawing = (LinkedList<ShapeObject>) ois.readObject();
	                		ObjectOutputStream oos;
	                		String fileName = "Drawings/"+fn;
                			oos = new ObjectOutputStream(new FileOutputStream(fileName));
                		    oos.writeObject(drawing);
                		    oos.close();
						} catch (ClassNotFoundException e) {e.printStackTrace();
						} catch (SecurityException e) {e.printStackTrace();
						}
                	}	
            	}
                else if(message.contains("<<OWNR>>")){
                	String newControlOwner = message.split(" ")[1];
                	chatServer.ownerOfControl = newControlOwner;
                	chatServer.broadcast("<<OWNR>> " + newControlOwner, "MDServer");
            	}
                else if(message.contains("<<BRDCSTUSRLST>>")){
                	chatServer.broadcastUserList();
            	}
                else if(message.contains("<<UPLOADNEWTOOLKIT>>")){
                	PrintWriter p = new PrintWriter(clientSock.getOutputStream(), true);
                	p.println("<<READYFORNEWTOOLKIT>>");
                	ObjectInputStream ois = new ObjectInputStream(clientSock.getInputStream());
                	ToolKit toolKit = (ToolKit) ois.readObject();
                	chatServer.toolKits.add(toolKit);
                	byte[] t = toolKit.getToolFi();
  	        		byte[] o = toolKit.getObjectFi();
  	        		File tFi = new File(toolKit.getName()+"Tool.class");
      	      	    FileOutputStream tfos = new FileOutputStream(tFi);
      	      	    tfos.write(t);
      	      	    tfos.close();
  	        		File oFi = new File(toolKit.getName()+"Object.class");
      	      	    FileOutputStream ofos = new FileOutputStream(oFi);
      	      	    ofos.write(o);
      	      	    ofos.close();
      	      	    chatServer.broadcastAndLast("<<UPLOADNEWTOOLKIT>>");
                	chatServer.broadcastToolKit(toolKit);
            	}
                else if(message.contains("<<READYFORTOOLKITS>>")){
                	ObjectOutputStream oos;
            		try{
            			oos = new ObjectOutputStream(clientSock.getOutputStream());
            		    chatServer.toolKits.add(new ToolKit("helloTool"));
            			oos.writeObject(chatServer.toolKits);
            		    oos.close();
            		}catch(IOException ioe){
            			System.out.println(ioe.getMessage());
            		}
                }
//------------------------------------------------------------------------------------
            }
        }
        catch (Exception e) 
        { 
        	chatServer.clientList.remove(clientSock);
        	int indexOfUserInList = chatServer.currentUsernames.indexOf(username);
        	chatServer.currentUsernames.remove(username);
        	try
            {
            	chatServer.broadcast("<<USRLFT>> " + username, "MDServer");
	        	if(chatServer.currentUsernames.size() == 0){
	        		chatServer.ownerOfControl = "";
	        	}
	        	else{
		        	if(username.equals(chatServer.ownerOfControl)){
		        		if(indexOfUserInList == chatServer.currentUsernames.size()){
		        			chatServer.ownerOfControl = (String)chatServer.currentUsernames.get(0);
		        		}else {
		        			chatServer.ownerOfControl = (String)chatServer.currentUsernames.get(indexOfUserInList);
		        		}
		               	chatServer.broadcast("<<OWNR>> " + chatServer.ownerOfControl, "MDServer");
		        	}
	        	}
	        	clientSock.close();
            }
            catch (Exception ex) 
            {
				System.out.println("Client socket closed unsuccessfully. Error: " + ex);
			}
        	
        }
    }
	public void sendToolKits(){
		ObjectOutputStream oos;
		try{
			oos = new ObjectOutputStream(clientSock.getOutputStream());
			oos.writeObject(chatServer.toolKits);
		}catch(IOException ioe){
			System.out.println(ioe.getMessage());
		}
	}
    public boolean getShapeObjects(){
		   try {
			   ObjectInputStream ois = new ObjectInputStream(clientSock.getInputStream());
			   chatServer.refreshShapeObjects((LinkedList<ShapeObject>)ois.readObject());
		   } catch (IOException e) {
			   e.printStackTrace();
			   return false;
		   } catch (ClassNotFoundException e) {
			   e.printStackTrace();
			   return false;
		   }catch (Exception e){
			   e.printStackTrace();
			   return false;
		   }
		   return true;
	   }
}